package com.nengchuan.eic.nceconomy.service;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nengchuan.eic.nceconomy.component.AsyncOperator;
import com.nengchuan.eic.nceconomy.component.excel.ExcelModel;
import com.nengchuan.eic.nceconomy.component.excel.ResponseModel;
import com.nengchuan.eic.nceconomy.constant.*;
import com.nengchuan.eic.nceconomy.dao.*;
import com.nengchuan.eic.nceconomy.entity.dto.ExcelDetailDTO;
import com.nengchuan.eic.nceconomy.entity.dto.ExcelInfoDTO;
import com.nengchuan.eic.nceconomy.entity.po.*;
import com.nengchuan.eic.nceconomy.entity.vo.*;
import com.nengchuan.eic.nceconomy.util.ExcelSerialNumUtils;
import com.nengchuan.model.model.WrappedResult;
import com.nengchuan.util.NullCheckUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;

/**
 * <p>
 * 原始和指标数据表 服务实现类
 * </p>
 *
 * @author luoping
 * @since 2020-04-23
 */
@Service
@Slf4j
public class OriginIndexDataServiceImpl extends ServiceImpl<OriginIndexDataMapper, OriginIndexData> implements OriginIndexDataService {

    @Autowired
    private OriginIndexDataMapper originIndexDataMapper;

    @Autowired
    private ExcelSheetMapper excelSheetMapper;

    @Autowired
    private ExcelFileMapper excelFileMapper;

    @Autowired
    private OssService ossService;

    @Autowired
    private AsyncOperator asyncOperator;

    @Autowired
    private TemplateSheetMapper templateSheetMapper;

    @Autowired
    private TemplateDicMapper templateDicMapper;

    @Autowired
    private VerifyResultService verifyResultService;

    @Autowired
    private IndexDictMapper indexDictMapper;

    /**
     * 查询详情
     *
     * @param excelDetailDTO 参数
     * @return 列表信息
     */
    @Override
    public SheetDetail getSheetDetail(ExcelDetailDTO excelDetailDTO) {
        //获取excel对应的模板阶段及表名
        SheetInfoVO sheetInfoVO = excelFileMapper.getSheetInfo(excelDetailDTO);
        if (sheetInfoVO == null) {
            return null;
        }
        //获取所有信息
        List<OriginIndexData> originIndexData = null;
        boolean fold = SheetFormatEnum.isFold(sheetInfoVO.getTemplateSheetName());
        if (fold) {
            originIndexData = originIndexDataMapper.selectSheetDetailOnParentNode(excelDetailDTO);
        } else {
            originIndexData = originIndexDataMapper.selectSheetDetailOrderByLineAndSeqAsc(excelDetailDTO);
        }
        if (originIndexData == null || originIndexData.size() == 0) {
            return null;
        }
        Map<Integer, List<OriginIndexData>> map = originIndexData.stream().collect(Collectors.groupingBy(OriginIndexData::getLineStartCoordinates, TreeMap::new, Collectors.toList()));
        //获取表头栏目
        List<HeadLineVO> headLineList = new ArrayList<>();
        SheetDataEnum sheetDataEnum = SheetDataEnum.getHeadlineNumByTemplateSheetName(sheetInfoVO.getTemplateSheetName());
        headLineList = headLine(map, headLineList, sheetDataEnum);
        //标题
        List<OriginIndexData> title = map.remove(SheetDataEnum.getTitleLineNumByTemplateSheetName(sheetInfoVO.getTemplateSheetName()));


        //获取表头
        List<OriginIndexData> tableHead = map.remove(SheetDataEnum.getTableheadLineNumByTemplateSheetName(sheetInfoVO.getTemplateSheetName()));
        List<HeadLineVO> tableHeadList = new ArrayList<>();
        for (OriginIndexData aTableHead : tableHead) {
            HeadLineVO headLineVO = new HeadLineVO();
            headLineVO.setKey(aTableHead.getValue());
            tableHeadList.add(headLineVO);
        }

        //获取表内容 （行）
        List<Map<String, Object>> content = new ArrayList<>();
        lineContent(map, content, sheetInfoVO.getTemplateId(), fold);
        return new SheetDetail(sheetInfoVO.getExcelName(), sheetInfoVO.getSheetName(), tableHeadList, headLineList, content);
    }

    /**
     * 获取表头
     *
     * @param map           数据
     * @param headLineList  表头
     * @param sheetDataEnum 表头开始行
     * @return 表头
     */
    private List<HeadLineVO> headLine(Map<Integer, List<OriginIndexData>> map, List<HeadLineVO> headLineList, SheetDataEnum sheetDataEnum) {
        if (!sheetDataEnum.getLineStartCoordinates().equals(sheetDataEnum.getLineEndCoordinates())) {
            //存在多级标题
            List<OriginIndexData> headLine = map.remove(sheetDataEnum.getLineStartCoordinates());
            for (int i = 0; i < headLine.size(); i++) {
                HeadLineVO headLineVO = new HeadLineVO();
                String value = headLine.get(i).getValue();
                if (value.contains("-")) {
                    String[] split = value.split("-");
                    StringBuilder sb = new StringBuilder();
                    for (int j = 0; j < split.length; j++) {
                        HeadLineVO vo = new HeadLineVO();
                        sb.append(split[j]);
                        vo.setKey(sb.toString());
                        if (j == split.length - 1) {
                            vo.setKey(value);
                            vo.setValue("key" + i);
                            if (!SheetFormatEnum.isExist(value)) {
                                vo.setFormat("1");
                            }
                        } else {
                            vo.setTitleChildren(new ArrayList<>());
                            sb.append("-");
                        }
                        if (headLineList.stream().noneMatch(x -> vo.getKey().equals(x.getKey()))) {
                            headLineList.add(vo);
                        }
                    }
                } else {
                    headLineVO.setKey(value);
                    headLineVO.setValue("key" + i);
                    if (!SheetFormatEnum.isExist(value)) {
                        headLineVO.setFormat("1");
                    }
                    headLineList.add(headLineVO);
                }
            }
            List<HeadLineVO> collect = headLineList.stream().filter(x -> x.getKey().contains("-")).collect(Collectors.toList());
            List<HeadLineVO> result = headLineList.stream().filter(x -> !x.getKey().contains("-")).collect(Collectors.toList());
            //生成多级标题
            getMultilevelTitle(collect, result);
            wipeOffSymbol(result);
            headLineList = result;

        } else {
            List<OriginIndexData> headLine = map.remove(sheetDataEnum.getLineStartCoordinates());
            for (int i = 0; i < headLine.size(); i++) {
                HeadLineVO headLineVO = new HeadLineVO();
                headLineVO.setKey(headLine.get(i).getValue());
                headLineVO.setValue("key" + i);
                if (!SheetFormatEnum.isExist(headLine.get(i).getValue())) {
                    headLineVO.setFormat("1");
                }
                headLineList.add(headLineVO);
            }
        }
        return headLineList;
    }

    /**
     * 获取行
     *
     * @param map     数据
     * @param content 内容
     */
    private void lineContent(Map<Integer, List<OriginIndexData>> map, List<Map<String, Object>> content, Long templateId, boolean fold) {
        Long parentId = null;
        boolean intoContent = false;
        TemplateSheet templateSheet = templateSheetMapper.judgeSheetByIdIsFisrt(templateId);
        for (Map.Entry<Integer, List<OriginIndexData>> entry : map.entrySet()) {
            List<OriginIndexData> value = entry.getValue();
            Map<String, Object> map1 = new HashMap<>();
            map1.put("id", value.get(0).getId());
            boolean isIntoParent = false;
            for (int i = 0; i < value.size(); i++) {
                OriginIndexData originIndexData1 = value.get(i);
                if (templateSheet == null) {
                    if (value.get(0).getParentId() != null) {
                        intoContent = false;
                        value.get(i).setParentId(value.get(0).getParentId());
                    } else {
                        intoContent = true;
                    }
                    if (value.get(0).getParentId() == null) {
                        parentId = originIndexData1.getId();
                    } else if (!value.get(0).getParentId().equals(parentId)) {
                        parentId = originIndexData1.getParentId();
                    } else {
                        if (!isIntoParent) {
                            searchAndIntoParent(content, parentId, map1);
                        }
                        isIntoParent = true;
                    }
                    if (StringUtils.isNotBlank(originIndexData1.getUnit())) {
                        map1.put("key" + i, originIndexData1.getValue() + "  " + originIndexData1.getUnit());
                    } else {
                        map1.put("key" + i, originIndexData1.getValue());
                    }
                } else {
                    intoContent = true;
                    map1.put("key" + i, originIndexData1.getValue());
                }
            }
            if (intoContent) {
                if (fold) {
                    Object key0 = map1.get("key0");
                    if (ExcelSerialNumUtils.isUpperSeq((String) key0)) {
                        map1.put("hasChildren", fold);
                    }
                }
                content.add(map1);
            }
        }
    }

    /**
     * 内容---将子信息放入父信息中
     *
     * @param content  结果集合
     * @param parentId 父节点id
     * @param map1     新生成的子信息
     */
    private void searchAndIntoParent(List<Map<String, Object>> content, Long parentId, Map<String, Object> map1) {
        for (Map<String, Object> c : content) {
            List<Map<String, Object>> children = (List<Map<String, Object>>) c.get("children");
            if (parentId.equals(Long.valueOf(c.get("id").toString()))) {
                if (children == null) {
                    children = new ArrayList<>();
                    children.add(map1);
                    c.put("children", children);
                } else {
                    children.add(map1);
                }
            } else if (children != null) {
                searchAndIntoParent(children, parentId, map1);
            }
        }
    }

    /**
     * 将结果集中的-去掉
     *
     * @param result
     */
    private void wipeOffSymbol(List<HeadLineVO> result) {
        result.forEach(x -> {
            if (x.getKey().contains("-")) {
                String[] split = x.getKey().split("-");
                x.setKey(split[split.length - 1]);
            }
            List<HeadLineVO> titleChildren = x.getTitleChildren();
            if (titleChildren != null) {
                titleChildren.forEach(y -> {
                    if (y.getKey().contains("-")) {
                        String[] split = y.getKey().split("-");
                        y.setKey(split[split.length - 1]);
                    }
                    if (y.getTitleChildren() != null && y.getTitleChildren().size() > 0) {
                        wipeOffSymbol(y.getTitleChildren());
                    }
                });
            }
        });
    }

    /**
     * 获取多级标题
     *
     * @param containCollet   包含-的标题
     * @param noContainCollet 不包含-的标题
     */
    private void getMultilevelTitle(List<HeadLineVO> containCollet, List<HeadLineVO> noContainCollet) {
        if (containCollet.size() == 0) {
            return;
        }
        List<HeadLineVO> collect = new ArrayList<>();
        noContainCollet.forEach(x -> {
            containCollet.forEach(y -> {
                if (y.getKey().startsWith(x.getKey())) {
                    String replace = y.getKey().replace(x.getKey(), "");
                    if (!replace.substring(1).contains("-")) {
                        x.getTitleChildren().add(y);
                        collect.add(y);
                    }
                }
            });
        });
        containCollet.removeAll(collect);
        getMultilevelTitle(containCollet, collect);
    }

    /**
     * 查询excel  sheetList
     *
     * @param excelId@return
     */
    @Override
    public ExcelSheetListVO getSheetList(String excelId) {
        ExcelSheetListVO listVO = new ExcelSheetListVO();
        List<SheetVO> list = excelSheetMapper.selectSheetList(excelId);
        list.forEach(x -> {
//            x.setColour(SheetEnum.getColourBName(x.getSheetTemplateName()));
//            if(CommonConstant.SheetCateGory.IMPORTANCE.equals(SheetEnum.getCategroyBName(x.getSheetTemplateName()))){
            x.setFold(SheetFormatEnum.isFold(x.getSheetTemplateName()));
            listVO.getImportanceSheet().add(x);

//            }else if(CommonConstant.SheetCateGory.MINOR.equals(SheetEnum.getCategroyBName(x.getSheetTemplateName()))){
//                listVO.getMinorSheet().add(x);
//            }else {
//                listVO.getOtherSheet().add(x);
//            }
        });
        return listVO;
    }

    @Override
    public String download(String excelId) throws Exception {
        ExcelFile excelFile = excelFileMapper.selectById(excelId);
        if (excelFile == null) {
            return null;
        }
        WrappedResult<OssFileReseponseVO> filesFromOssById = ossService.getFilesFromOssById(excelFile.getOssId());
        if (filesFromOssById != null && filesFromOssById.getData() != null) {
            return filesFromOssById.getData().getUrl();
        }
        return null;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public ExcelInfoDTO save(ResponseModel responseModel, ExcelVerify excelVerify, ExcelFile excelFile, Long userId, String realName) throws InterruptedException {

        List<VerifyResult> verifyResults = responseModel.getVerifyResults();
        verifyResults.forEach(x -> x.setExcelName(excelFile.getExcelName()));
        verifyResultService.insertList(excelVerify, verifyResults);

        //如果用户有历史数据,则进行逻辑删除
        QueryWrapper<ExcelFile> wrapper = new QueryWrapper<>();
        wrapper.eq("template_id", excelFile.getTemplateId());
        wrapper.eq("pid", excelFile.getPid());
        if (excelFile.getProjectId() == null) {
            wrapper.isNull("project_id");
        } else {
            wrapper.eq("project_id", excelFile.getProjectId());
        }
        List<Long> ids = excelFileMapper.selectList(wrapper).stream().map(ExcelFile::getId).collect(Collectors.toList());
        if (NullCheckUtils.isNotNull(ids)) {
            excelFileMapper.logicDeleteByIdIn(ids, userId, realName, System.currentTimeMillis());
            excelSheetMapper.logicDeleteByExcelIdIn(ids, userId, realName, System.currentTimeMillis());
            originIndexDataMapper.logicDeleteByExcelIdIn(ids, userId, realName, System.currentTimeMillis());
        }

        excelFile.setCreateId(userId);
        excelFile.setCreateName(realName);
        excelFile.setCreateTime(System.currentTimeMillis());
        excelFileMapper.insert(excelFile);

        List<ExcelModel> excelModels = responseModel.getExcelModels();
        for (int i = 0; i < excelModels.size(); i++) {
            ExcelModel excelModel = excelModels.get(i);
            ExcelSheet sheet = excelModel.getExcelSheet();
            sheet.setExcelId(String.valueOf(excelFile.getId()));
            sheet.setCreateId(userId);
            sheet.setCreateName(realName);
            sheet.setCreateTime(System.currentTimeMillis());
            excelSheetMapper.insert(sheet);
        }

        int size = 0;
        for (int i = 0; i < excelModels.size(); i++) {
            size += excelModels.get(i).getOriginIndexData().size();
        }

        List<OriginIndexData> originIndexDataPOs = new ArrayList<>(size);
        for (int i = 0; i < excelModels.size(); i++) {
            ExcelModel excelModel = excelModels.get(i);
            ExcelSheet sheet = excelModel.getExcelSheet();
            List<OriginIndexData> originIndexDatas = excelModel.getOriginIndexData();
            originIndexDatas.forEach(e -> {
                e.setSheetId(sheet.getId());
                e.setExcelId(excelFile.getId());
                e.setCreateId(userId);
                e.setCreateName(realName);
                e.setCreateTime(System.currentTimeMillis());
            });
            originIndexDataPOs.addAll(originIndexDatas);
        }

        originIndexDataMapper.insertList(originIndexDataPOs);

        Long sheetId = null;
        if (NullCheckUtils.isNotNull(excelModels) && NullCheckUtils.isNotNull(excelModels.get(0))) {
            sheetId = excelModels.get(0).getExcelSheet().getId();
        }
        ExcelInfoDTO excelInfoDTO = ExcelInfoDTO
                .builder()
                .excelId(excelFile.getId())
                .sheetId(sheetId)
                .build();

        return excelInfoDTO;
    }

    /**
     * 通过projectId获取excel第一张表的id
     *
     * @param projectId
     * @param category
     * @param project
     * @param version
     * @return
     */
    @Override
    public ExcelDetailDTO getSheetOneId(String pid, String projectId, String category, String project, String version) {
        return excelFileMapper.getFirstSheet(pid, projectId, category, project, version);
    }

    /**
     * 根据父id查询sheetList
     *
     * @param id
     * @return
     */
    @Override
    public List<Map<String, Object>> getSheetListByPid(Long id, Long sheetId) {
        List<OriginIndexDataHaveSon> originIndexData = originIndexDataMapper.getSheetListByPid(id, sheetId);
        List<Map<String, Object>> content = new ArrayList<>();
        TreeMap<Integer, List<OriginIndexDataHaveSon>> collect = originIndexData.stream().collect(Collectors.groupingBy(OriginIndexDataHaveSon::getLineStartCoordinates, TreeMap::new, Collectors.toList()));
        for (Map.Entry<Integer, List<OriginIndexDataHaveSon>> entry : collect.entrySet()) {
            List<OriginIndexDataHaveSon> value = entry.getValue();
            Map<String, Object> map1 = new HashMap<>();
            map1.put("id", value.get(0).getId());
            for (int i = 0; i < value.size(); i++) {
                OriginIndexDataHaveSon originIndexData1 = value.get(i);
                map1.put("key" + i, originIndexData1.getValue());
            }
            map1.put("hasChildren", value.get(0).getHaveSon() != null);
            content.add(map1);
        }
        return content;
    }

    /**
     * 根据指标及模板sheetId查询相应数据
     *
     * @param index
     * @param sheetName
     * @param category
     * @param projectId
     * @param pid
     * @return
     */
    @Override
    public IndexSearchResultVO indexSearchData(String index, String sheetName, List<String> category, String projectIndex, Long projectId, Long pid) {
        IndexSearchResultVO vo = new IndexSearchResultVO();
        //查询符合条件的值
        List<IndexSearchVO> originIndexDataList = originIndexDataMapper.findValueByParams(index, sheetName, category, projectIndex, projectId, pid);
        if(CollectionUtils.isNotEmpty(originIndexDataList)){
            //查询标题
//            List<String> collect = originIndexDataList.stream().map(IndexSearchVO::getRowIndex).distinct().sorted(String::compareTo).collect(Collectors.toList());

//            if (CollectionUtils.isEmpty(rowNames)) {
//                rowNames = indexDictMapper.findByCodesSettle(collect);
//            }
            List<String> categoryBySheetName = templateSheetMapper.getCategoryBySheetName(sheetName);


            List<String> collect=templateDicMapper.getTitleBySheetName(sheetName,SheetDataEnum.getHeadlineNumByTemplateSheetName(sheetName).getLineStartCoordinates());
            List<IndexDict> rowNames;
            if(categoryBySheetName.contains(CategoryEnum.SETTLE.code)){
                rowNames=indexDictMapper.findByNamesAndProjectIndexSettleRow(collect,projectIndex);
            }else{
                rowNames=indexDictMapper.findByNamesAndProjectIndexRow(collect,projectIndex);
            }
            //根据collect排序
            rowNames = orderByCollect(collect, rowNames);
            IndexSearchResultVO.Content content1 = new IndexSearchResultVO.Content();

            List<HeadLineVO> row = rowNames.stream().map(x->{
                HeadLineVO headLineVO=new HeadLineVO();
                headLineVO.setValue(x.getName());
                headLineVO.setKey(x.getCode());
                return headLineVO;
            }).collect(Collectors.toList());
            List<Map<String,String>> content = new ArrayList<>();
            content1.setContent(content);
            content1.setHeadLine(row);
            List<IndexSearchResultVO.Properties> properties = new ArrayList<>();

            TreeMap<Long, List<IndexSearchVO>> sheetData = originIndexDataList.stream().collect(Collectors.groupingBy(IndexSearchVO::getSheetId, TreeMap::new, Collectors.toList()));
            for (Map.Entry<Long, List<IndexSearchVO>> entry : sheetData.entrySet()) {
                List<IndexSearchVO> value = entry.getValue();
                TreeMap<Integer, List<IndexSearchVO>> collect1 = value.stream().collect(Collectors.groupingBy(IndexSearchVO::getLineStartCoordinates, TreeMap::new, Collectors.toList()));
                for (Map.Entry<Integer, List<IndexSearchVO>> entry1 : collect1.entrySet()) {
                    List<IndexSearchVO> value1 = entry1.getValue();
                    Map<String,String> line=new HashMap<>();
                    row.forEach(x->{
                        line.put(x.getKey(),value1.stream().filter(y->y.getRowIndex().equals(x.getKey())).map(IndexSearchVO::getValue).findFirst().orElse(""));

                    });
                    properties.add(new IndexSearchResultVO.Properties(value1.get(0)));
                    content.add(line);
                }
            }

            vo.setContent(content1);
            vo.setProperties(properties);
        }
        return vo;
    }



    public List<IndexDict> orderByCollect(List<String> collect,List<IndexDict> rowNames){
        List<IndexDict> list=new ArrayList<>();
        collect.forEach(x->{
            rowNames.forEach(y->{
                if(x.endsWith(y.getName())){
                    list.add(y);
                }
            });
        });
        return list;
    }

}
